<?php

namespace Theatre;

class Dispatcher {
	/* 
	 * @var _controller the current controller
	 */
	private $_controller = null;

	/*
	 * @var _url the current url
	 */
	private $_url = null;

	/*
	 * @var _docRoot the document root
	 */
	private $_docRoot = null;

	/*
	 * @var config
	 */
	private $_config = null;


	/**
	 * Base
	 */
	public $base;


	/**
	 * Constructor
	 */
	function __construct($config) {
		$this->_config  = $config;
		$this->_docRoot = $config['docRoot'];

		$this->baseUrl();

		$this->_run();
	}


	/**
	 * Run the given URL
	 */
	private function _run() {
		$this->_url = empty($_GET['url']) ? null : $_GET['url'];

		// Red lights where .. found, counteract the lookup
		if (preg_match('/\.{2, }/', $this->_url)) {
			throw new \Exception('Invalid URL');
		}

		$parsedUrl = explode('/', $this->_url);

		// TODO need a smarter way of finding out the name
		$controllerName = empty($parsedUrl[0]) ? 'Root' : ucfirst(strtolower($parsedUrl[0]));
		$action         = empty($parsedUrl[1]) ? 'index' : $parsedUrl[1];

		$this->_getController($controllerName);

		if (!is_object($this->_controller)) {
			throw new \Exception('Missing Controller');
		}

		$this->_controller->url     = $this->_url;
		$this->_controller->action  = $action;
		$this->_controller->name    = $controllerName;
		$this->_controller->params  = $this->_parseParams();
		$this->_controller->base    = $this->base;

		return $this->_invoke();
	}


	/**
	 * Parses the request params
	 */
	private function _parseParams() {
		$params = array();

		if (isset($_POST)) {
			$params = $_POST;
			if (ini_get('magic_quotes_gpc') === '1') {
				$params = stripslashes_deep($params);
			}

		}

		if (isset($_GET)) {
			if (ini_get('magic_quotes_gpc') === '1') {
				$url = stripslashes_deep($_GET);
			}
			else {
				$url = $_GET;
			}

			$params = array_merge($params, $url);
		}

		foreach ($_FILES as $name => $data) {
			if ($name != 'data') {
				$params[$name] = $data;
			}
		}


		return $params;
	}


	/**
	 * Invoke controller method
	 */
	private function _invoke() {
		$methods = array_flip(get_class_methods($this->_controller));

		if (!isset($methods[$this->_controller->action])) {
			throw new \Exception("Missing action {$this->_controller->action}");
		}

		$this->_controller->invoke();

		if (empty($this->_controller->noTemplate)) {
			echo $this->_controller->render();
		}
		else {
			echo $this->_controller->body;
		}
	}


	/**
	 * Get and load the controller
	 */
	private function _getController($controllerName) {
		// name path representation
		$namespacePath = str_replace('\\', '/', $this->_config['namespace']);

		// find out if the controller exists
		// if it does, load it and instantiate it
		$controllerPath = $this->_docRoot . '/' . $namespacePath . "/{$controllerName}.php";
		if (!file_exists($controllerPath)) {
			throw new \Exception("Missing conroller file {$controllerPath}");
		}

		$class = $this->_config['namespace'] . "\\{$controllerName}";

		if (!class_exists($class)) {
			throw new \Exception("Missing conroller class {$class}");
		}

		$this->_controller = new $class($this->_config);
	}

	
	/**
	 * Determine base URL
	 */
	private function baseUrl() {
		$this->base = str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']);
	}
}
